home *** CD-ROM | disk | FTP | other *** search
/ Programming Sound Cards / Programming Sound Cards.iso / sound_57 / sampler.inc < prev    next >
Text File  |  1995-01-01  |  43KB  |  1,451 lines

  1.  
  2. { Utility procedures for sampler.pas}
  3.  
  4.  
  5. {$f+}
  6. procedure samplerexit; {$f-}
  7.  
  8. { incase graphics mode, restore text screen before error message is given
  9.   also restores keyboard interrupt on abort}
  10.  
  11. begin {samplerexit}
  12. mem[0 : $417] := mem[0 : $417] And $fc; {shift off}
  13. restorecrtmode;
  14. exitproc:=exitsave;
  15. if showerrormessage then
  16.   writeln('Exit due to internal error!');
  17. if customkbd then
  18.   restore;
  19. end; {samplerexit}
  20.  
  21.  
  22. function index(position:longint):longint;
  23.  
  24. { calculates buffer array index for given screen position}
  25.  
  26. begin {index}
  27. if zoom then
  28.   index:=viewleft+position - plotxoffset
  29. else
  30.   index:=Round((position - plotxoffset)
  31.          / (getmaxx - 2 * plotxoffset) * bufflength);
  32. end;{index}
  33.  
  34. function scaleord(index:longint):integer;
  35.  
  36. { calculates screen position for indexth position in buffer array}
  37.  
  38. begin {scaleord}
  39. if zoom then
  40.   scaleord:=index-viewleft+plotxoffset
  41. else
  42.   scaleord:= Round(index / bufflength * (getmaxx - 2 * plotxoffset)
  43.                    + plotxoffset); {move to end of read data}
  44. end; {scaleord}
  45.  
  46.  
  47.   Function keypress : Boolean;
  48.  
  49.     { assumes custom keyboard service is installed. checks if a key has been
  50.     pressed and released}
  51.  
  52.   Begin
  53.     If kbdflag > 0 Then
  54.       Case keyval Of
  55.         42 : mem[0 : $417] := mem[0 : $417] Or 2; {lshift down}
  56.         54 : mem[0 : $417] := mem[0 : $417] Or 1; {rshift down}
  57.         170 : mem[0 : $417] := mem[0 : $417] And $fd; {lshift release}
  58.         182 : mem[0 : $417] := mem[0 : $417] And $fe; {rshift release}
  59.       End;                        {case}
  60.     keypress := (kbdflag > 0) And (keyval < 128);
  61.   End;  {keypress}
  62.  
  63.  
  64.  
  65.   Function get_inc(tune : Integer; c : Char) : Integer;
  66.  
  67.     { returns a fractional increment value for a given key based on 12th root
  68.       of 2}
  69.  
  70.   Begin
  71.     get_inc := Round(tune * Exp(kbdmap[c] * 0.057762265));
  72.                             {= (12th root of 2)^kbdmap[c] * tune}
  73.   End;   {get_inc}
  74.  
  75.  
  76.   Procedure display_title(title_string:string; font, fontsize,
  77.                           bcolor,color:word);
  78.  
  79.     { displays nice big bold title}
  80.  
  81.   Begin
  82.     settextstyle(font, horizdir, fontsize);
  83.     settextjustify(centertext, toptext);
  84.     panel(getmaxx Div 2, 1, getmaxx-cornersize*2, Round(textheight(titlestring) * 1.1),
  85.       bcolor);
  86.     selectcolor(color);
  87.     outtextxy(getmaxx Div 2, - 4, title_string);
  88.   End;   {display_title}
  89.  
  90.  
  91.   Procedure display_pointers(leftord,rightord,loopord:longint;
  92.                              leftshow,rightshow,loopshow:boolean);
  93.  
  94.     { displays up to 3 pointers}
  95.  
  96.   Begin
  97.     if leftshow and (leftord>=viewleft) and (leftord<=viewright) then
  98.       putimage(scaleord(leftord) - arrowxoff, arrowlowy, uparrowp^, xorput);
  99.     if rightshow and (rightord<=viewright) and (rightord<=viewright) then
  100.       putimage(scaleord(rightord) - arrowxoff, arrowlowy, uparrowp^, xorput);
  101.     if loopshow and (loopord>=viewleft) and (loopord<=viewright) then
  102.       putimage(scaleord(loopord) - arrowxoff, arrowhighy, downarrowp^, xorput);
  103.   End;                            {display_pointers}
  104.  
  105.  
  106.   Procedure highlight_directory_entry(fileno : Integer; extension:boolean;
  107.                                       highlight : Boolean);
  108.  
  109.     { highlights the currently selected file or restores if highlight=false
  110.       if extension=true then the file extension is shown also}
  111.  
  112.   Var j, x, y : Integer;
  113.     str1 : String;
  114.  
  115.   Begin
  116.     settextstyle(smallfont, horizdir, 4);
  117.     settextjustify(lefttext, toptext);
  118.     str1:=copy(bigemptystring,1,dirnamefieldwidth);
  119.     j := pos('.', dir[fileno]);
  120.     if extension or (j=0) then
  121.        j:=succ(length(dir[fileno]));
  122.     If highlight Then
  123.       Begin
  124.         selectcolor(dirhcolor);
  125.         selectfillstyle(solidfill, dircolor);
  126.       End
  127.     Else
  128.       Begin
  129.         selectcolor(dircolor);
  130.         selectfillstyle(solidfill, dirbcolor);
  131.       End;
  132.     x := cornersize
  133.          + (Pred(fileno) Mod dirnamesperline) * textwidth(str1);
  134.     y := directoryyoff
  135.          + Pred(fileno) Div dirnamesperline * textheight(' ');
  136.     bar(x, y+1, x + textwidth(Copy(str1, 1, 8)),
  137.         y + textheight(' ') );
  138.     outtextxy(x, y, Copy(dir[fileno], 1, Pred(j)));
  139.   End;  {highlight_directory_entry}
  140.  
  141.  
  142.   Procedure getdirectory(Var dir : directory_type; pattern : String);
  143.  
  144.     {read file names in current directory matching pattern to dir}
  145.  
  146.   Var dirinfo : searchrec;
  147.     fileno,i : Integer;
  148.  
  149.   Begin
  150.     findfirst(path+'\'+pattern, 0, dirinfo);
  151.     fileno := 1;
  152.     While doserror = 0 Do
  153.       Begin
  154.         dir[fileno] := dirinfo.name;
  155.         i:=pos('.',dir[fileno]);
  156.         if i in [1..8] then
  157.           dir[fileno]:=copy(copy(dir[fileno],1,pred(i))+'        ',1,8)+
  158.                        copy(dir[fileno],i,4);    {right justify extension}
  159.         Inc(fileno);
  160.         findnext(dirinfo);
  161.       End;
  162.     dir[fileno] := '';            {mark end of list}
  163.   End; {getdirectory}
  164.  
  165.  
  166.   Procedure showdirectory(extension:string);
  167.  
  168.     { displays files with extension in current directory}
  169.  
  170.  
  171.   var i,j,k:integer;
  172.  
  173.   Begin
  174.     settextstyle(smallfont, horizdir, 5);
  175.     settextjustify(lefttext, toptext);
  176.     fill_background(dirbcolor,solidfill,cornersize);
  177.     selectcolor(dircolor);
  178.     getdirectory(dir, '*.'+extension);
  179.     if extension='*' then
  180.       extension:='All';
  181.     outtextxy(cornersize, 0, extension+' files on  ' +
  182.               path);
  183.     directoryyoff:=round(textheight(' ')*1.3);
  184.     i := 1;
  185.     While (dir[i]<>'') and (dir[Succ(i)] <> '') Do   {sort dir}
  186.       Begin
  187.         j := Succ(i);
  188.         While dir[j] <> '' Do
  189.           Begin
  190.             If dir[j] < dir[i] Then {name out of sequence}
  191.               Begin
  192.                 str1 := dir[j];
  193.                 For k := Pred(j) Downto i Do {shift names down list}
  194.                   dir[Succ(k)] := dir[k];
  195.                 dir[i] := str1;   {insert name in correct place}
  196.               End;
  197.             j := Succ(j);
  198.           End;
  199.         i := Succ(i);
  200.       End;
  201.     str1 := '';
  202.     For i := 1 To dirnamefieldwidth Do
  203.       str1 := str1 + ' ';
  204.     i := 1;
  205.     While dir[i] <> '' Do
  206.       Begin
  207.         highlight_directory_entry(i, (extension='All'),False);
  208.         i := Succ(i);
  209.       End;
  210.     filesavail := Pred(i);
  211.     settextstyle(smallfont, horizdir, 4);
  212.     settextjustify(lefttext, toptext);
  213.     Str(diskfree(0) shr 10, str1);
  214.     outtextxy(cornersize,
  215.               directoryyoff+(filesavail div dirnamesperline +1)
  216.               *textheight(' '),' With ' + str1 + ' k free');
  217.   End;  {showdirectory}
  218.  
  219.  
  220.   procedure pickfile(extension:string; var pick:string);
  221.  
  222.   { shows directory list, then allows file selection by mouse or naming
  223.    specifically}
  224.  
  225.   var j:integer;
  226.       c:char;
  227.       cp:clickboxtypep;
  228.       dp:dialogentryp;
  229.       manual:boolean;
  230.  
  231.   function strip(s:string):string;
  232.  
  233.   { strips spaces from string and converts to lower case}
  234.  
  235.   var i:integer;
  236.  
  237.   begin
  238.   i:=pos(' ',s);
  239.   while i>0 do
  240.   begin
  241.     delete(s,i,1);
  242.     i:=pos(' ',s);
  243.   end;
  244.   for i:=1 to length(s) do
  245.     if s[i] in ['A'..'Z'] then
  246.       s[i]:=chr(ord(s[i])+ord('a')-ord('A'));
  247.   strip:=s;
  248.   end; {strip}
  249.  
  250. function selection:integer;
  251.  
  252. { determines which (if any) file bar was selected}
  253.  
  254. var boxwidth,boxheight,sel:integer;
  255.  
  256. begin {selection}
  257. boxwidth:=textwidth(copy(bigemptystring,1,dirnamefieldwidth));
  258. boxheight:=textheight(' ');
  259. if   (mousex>cornersize) and
  260.      (mousex-cornersize<boxwidth*dirnamesperline) and
  261.      ((mousex -cornersize) mod boxwidth
  262.       < textwidth(copy(bigemptystring,1,8))) and
  263.      (mousey>directoryyoff) and
  264.      (mousey-directoryyoff
  265.       <(pred(filesavail) div dirnamesperline +1)*boxheight) then
  266. begin
  267.   sel:=(mousex-cornersize) div boxwidth +
  268.        ((mousey-directoryyoff) div boxheight )*dirnamesperline+1;
  269.   if sel>filesavail then
  270.     selection:=-1
  271.   else
  272.     selection:=sel;
  273. end
  274. else
  275.   selection:=-1;
  276. end; {selection}
  277.  
  278.  
  279.   begin {pickfile}
  280.     mousearrowoff;
  281.     showdirectory(extension);
  282.     settextstyle(defaultfont,horizdir,1);
  283.     selectcolor(dialogcolor);
  284.     selectfillstyle(solidfill,dialogbcolor);
  285.     new(cp);
  286.     with cp^ do
  287.     begin
  288.       ttype:=_text;
  289.       title:='Specify input file';
  290.       x:=0;
  291.       y:=0;
  292.       next:=nil;
  293.     end;
  294.     draw_clicklist(cp,cornersize,getmaxy-textheight(' ')*2,clickbcolor,clickcolor);
  295.     mousearrowon;
  296.     j:=-1;
  297.     settextstyle(smallfont, horizdir, 4);
  298.     settextjustify(lefttext, toptext);
  299.     manual:=false;
  300.     repeat
  301.       repeat
  302.         c:=trackmouse;
  303.       until (mousekeys>0) or (c in [^c,^m]);
  304.       if c=^m then
  305.         manual:=true;
  306.       if mousekeys>1 then
  307.       begin
  308.         pick:='';
  309.         j:=0;
  310.       end
  311.       else
  312.       if mousekeys=1 then
  313.       begin
  314.         settextstyle(defaultfont,horizdir,1);
  315.         if click_selection(cp,cornersize,getmaxy-textheight(' ')*2)>-1 then
  316.         begin
  317.           draw_clicklist(cp,cornersize,getmaxy-textheight(' ')*2,clickcolor,
  318.                          clickbcolor);
  319.           manual:=true;
  320.         end
  321.         else
  322.         begin
  323.           settextstyle(smallfont,horizdir,4);
  324.           j:=selection;
  325.         end;
  326.       end
  327.       else
  328.         j:=-1;
  329.     until (j>-1) or manual or (c=^c);
  330.     mousearrowoff;
  331.     if not manual and (j>0) and (dir[j]<>'') then
  332.     begin
  333.       highlight_directory_entry(j, (extension='*'),true);
  334.       pick:=dir[j];
  335.       repeat
  336.         j:=pos(' ',pick);
  337.         if j>0 then
  338.           delete(pick,j,1);
  339.       until j=0;
  340.     end;
  341.     if manual then
  342.           Begin
  343.             new(dp);
  344.             with dp^ do
  345.             begin
  346.               title:='Name of input file (.'+extension+') (' + #17 +'--+ to skip):';
  347.               argtype:=_string;
  348.               ssize:=30;
  349.               stringresult:='';
  350.               next:=nil;
  351.             end;
  352.             settextstyle(defaultfont,horizdir,1);
  353.             dialog_box(dp,dialogbcolor,dialogcolor,false);
  354.             pick:=dp^.stringresult;
  355.             dispose(dp);
  356.             if (pick<>'') and (pos('.',pick)=0) then
  357.               pick:= strip(pick + '.'+extension);
  358.           End;
  359.     mousearrowon;
  360.     dispose(cp);
  361.   end; {pickfile}
  362.  
  363.  
  364. procedure cut_region(cutleft,cutright:longint);
  365.  
  366. { clears area of buffer following a cut operation}
  367.  
  368. begin {cut_region}
  369. fillchar(buffer^[cutleft],cutright-cutleft+1,127);
  370. end; {cut_region}
  371.  
  372. procedure set_bounds;
  373.  
  374. { recalculates boundary values for current pointer positions}
  375.  
  376. begin {set_bounds}
  377. {$ifdef pwm}
  378.         bufstart := Ofs(bufferw^[leftord]);
  379.         bufend := Ofs(bufferw^[rightord]);
  380.         bufloop := Ofs(bufferw^[loopord]);
  381. {$else}
  382.         bufstart := Ofs(buffer^[leftord]);
  383.         bufend := Ofs(buffer^[rightord]);
  384.         bufloop := Ofs(buffer^[loopord]);
  385. {$endif}
  386. end; {set_bounds}
  387.  
  388.  
  389.   procedure move_pointers(d1,d2,d3:integer);
  390.  
  391.     { move pointers by given delta values}
  392.  
  393.   var lefttemp,righttemp,looptemp:longint;
  394.       unlimited:boolean;
  395.  
  396.   Begin
  397.     lefttemp:=leftord;
  398.     righttemp:=rightord;
  399.     looptemp:=loopord;
  400.     leftord:=leftord+index(d1-viewleft+plotxoffset);
  401.     rightord:=rightord+index(d2-viewleft+plotxoffset);
  402.     loopord:=loopord+index(d3-viewleft+plotxoffset);
  403.     If leftord < 0 Then
  404.       leftord := 0;
  405.     If rightord > bufflength Then
  406.       rightord := bufflength;
  407.     If rightord < getmaxx div 5 Then
  408.       rightord := getmaxx div 5;
  409.     If leftord >= rightord-getmaxx div 5 Then
  410.       leftord := rightord - getmaxx div 5;
  411.     If loopord > rightord -getmaxx div 5 Then  {don't let arrows overlap}
  412.       loopord := rightord - getmaxx div 5;
  413.     If loopord < leftord Then
  414.       loopord := leftord;
  415.     display_pointers(lefttemp,righttemp,looptemp,(lefttemp<>leftord),
  416.                      (righttemp<>rightord),(looptemp<>loopord)); {erase pointers}
  417.     display_pointers(leftord,rightord,loopord,(lefttemp<>leftord),
  418.                      (righttemp<>rightord),(looptemp<>loopord)); {show pointers}
  419.   End;   {move_pointers}
  420.  
  421.  
  422.   procedure load_sound_file(fn : String; leftlimit,rightlimit:longint;
  423.                             mix:boolean);
  424.  
  425. { reads given sound file to the buffer. limits determine edges of allowed
  426.   region for loading. if sound file won't fit, it will be truncated.
  427.   if mix is true, then new file will be mixed with old data}
  428.  
  429.   Var i,j,k : longint;
  430.     f : File;
  431.     lastdp,dp,dialoghead:dialogentryp;
  432.     reducecut,reduceoriginal,reduceall:boolean;
  433.     cutshift,originalshift:byte;
  434.     offset:integer;
  435.     storagep:pointer;
  436.  
  437.   Begin
  438.     if (fn[1]<>'\') and (fn[2]<>':') then
  439.       Assign(f, path+'\'+fn)
  440.     else
  441.       Assign(f, fn);
  442.     {$i-}
  443.     Reset(f);
  444.     {$i+}
  445.     If IoResult = 0 Then
  446.       Begin
  447.         i:=0;
  448.         for i:=1 to filesize(f) div (blocksize div 128) do {read whole blocks}
  449.           BlockRead(f, bufferw^[pred(i) * blocksize], blocksize shr 7);
  450.         for j:=1 to filesize(f) mod (blocksize div 128) do {read what's left}
  451.           BlockRead(f, bufferw^[i * blocksize+pred(j)*128], 1);
  452.         loopord := bufferw^[2] + longint(bufferw^[3]) * 256 + plotxoffset;
  453.         i := bufferw^[0] + longint(bufferw^[1]) * 256; {get sample size}
  454.  
  455.         j:=rightlimit-leftlimit;
  456.         if i<j then
  457.           j:=i;   {copy size is smallest of file size and cutbox size}
  458.         if leftord>leftlimit then
  459.           leftord:=leftlimit;
  460.         if cutboxactive then
  461.         begin
  462.           if j+leftlimit>rightord then
  463.             rightord:=j+leftlimit;
  464.         end
  465.         else
  466.           rightord := j; {move to end of read data}
  467.         if not mix then
  468.           Move(bufferw^[4], buffer^[leftlimit],j)
  469.                                                   {shift work buffer to buffer}
  470.         else
  471.         begin
  472.           dialoghead:=nil;
  473.           new(dp);
  474.           with dp^ do
  475.           begin
  476.             title:='Reduce amplitude of cut file to fit (halve)?';
  477.             argtype:=_boolean;
  478.             booleanresult:=true;
  479.             next:=nil;
  480.           end;
  481.           add_dialogentry(dp,lastdp,dialoghead);
  482.           new(dp);
  483.           with dp^ do
  484.           begin
  485.             title:='Reduce amplitude of original to fit (halve)?';
  486.             argtype:=_boolean;
  487.             booleanresult:=true;
  488.             next:=nil;
  489.           end;
  490.           add_dialogentry(dp,lastdp,dialoghead);
  491.           new(dp);
  492.           with dp^ do
  493.           begin
  494.             title:='If reducing original, reduce whole thing?';
  495.             argtype:=_boolean;
  496.             booleanresult:=true;
  497.             next:=nil;
  498.           end;
  499.           add_dialogentry(dp,lastdp,dialoghead);
  500.           settextstyle(defaultfont,horizdir,1);
  501.           dialog_box(dialoghead,dialogbcolor,dialogcolor,true);
  502.           reducecut:=dialoghead^.booleanresult;
  503.           reduceoriginal:=dialoghead^.next^.booleanresult;
  504.           reduceall:=dialoghead^.next^.next^.booleanresult;
  505.           dispose(dialoghead);
  506.           cutshift:=ord(reducecut);
  507.           originalshift:=ord(reduceoriginal);
  508.           settextstyle(defaultfont,horizdir,1);
  509.           display_message('Calculating...',
  510.                            dialogbcolor,dialogcolor,storagep,true);
  511.           if reduceoriginal and reduceall then
  512.           begin
  513.             for i:=0 to leftlimit-1 do
  514.               buffer^[i]:=buffer^[i] shr 1+64;
  515.             for i:=leftlimit+j+1 to bufflength do
  516.               buffer^[i]:=buffer^[i] shr 1+64;
  517.           end;
  518.           offset:=integer(128)-128 shr originalshift-128 shr cutshift;
  519.           k:=leftlimit-4;
  520.           for i:=leftlimit to leftlimit+j do
  521. {$r-}        buffer^[i]:=integer(buffer^[i] shr originalshift)
  522.                         +bufferw^[i-k] shr cutshift+offset;
  523. {$ifdef debug}
  524. {$r+}   { switch range checking off above means overrange produces distortion}
  525. {$endif}
  526.           display_message('Calculating...',
  527.                            dialogbcolor,dialogcolor,storagep,false);
  528.         end;
  529.         set_bounds;
  530.         Close(f);            {must do this incase another read (assign) later}
  531.         workfile := fn;
  532.       End
  533.     Else
  534.       Begin
  535.         beep;
  536.         default_sound_file:='';
  537.         workfile:='';
  538.         leftord := 0;
  539.         rightord := bufflength;
  540.         loopord := leftord;
  541.         set_bounds;
  542.         new(dp);
  543.         dp^.next:=nil;
  544.         dp^.title:='Sound file '+workfile+' not found';
  545.         dp^.argtype:=_none;
  546.         settextstyle(defaultfont,horizdir,1);
  547.         dialog_box(dp,dialogbcolor,dialogcolor,true);
  548.         dispose(dp);
  549.       End;
  550.   End;  {load_sound_file}
  551.  
  552.  
  553.  
  554.   Procedure select_system(c : Char);
  555.  
  556.     { selects speed params for xt, xt turbo, at, at turbo}
  557.  
  558.   Begin
  559.     Case c Of
  560.       'X' :
  561.       Begin
  562.               tconstant := round(1.19318e3/14);    {timer constant for 14KHz }
  563.               systemname := 'XT';
  564.             end;
  565.       'T' :
  566.       Begin
  567.               tconstant := round(1.19318e3/22);     {timer constant for 22KHz }
  568.               systemname := 'XT turbo';
  569.             end;
  570.       'A' :
  571.       Begin
  572.               tconstant := round(1.19318e3/30);    {timer constant for 30kHz }
  573.               systemname := 'AT';
  574.             end;
  575.       'U' :
  576.       Begin
  577.               tconstant := round(1.19318e3/45);    {timer constant for 45kHz }
  578.               systemname := 'AT turbo';
  579.             end;
  580.     End;                          {case}
  581.     If c In ['X', 'T', 'A', 'U'] Then
  582.       Begin
  583.         incdef:=round(default_samplerate*(tconstant/1.1938e3)*256)+1;
  584.         sysspeed:=incdef;   {incase pwm, this indicates system speed factor}
  585.  
  586. {$ifdef pwm}
  587.     if c in ['X','T'] then
  588.           tconstant:=round(1.19318e3/16)
  589.         else
  590.           tconstant := round(1.19318e3/20);
  591.         incdef:=round(default_samplerate*(tconstant/1.1938e3)*256)+2;
  592. {$endif pwm}
  593.  
  594.         increment := incdef;
  595.         tune := increment;
  596.         crotchet:=round(60.0/tconstant*100);
  597.                                   {tinterval for a crotchet}
  598.         modulus:=round(0.25*1.19318e6/crotchet/tconstant);
  599.                              {set duration decrement rate for crotchet=.25 sec}
  600.       End;
  601.   End;  {select_system}
  602.  
  603. function get_daport(s:string):word;
  604.  
  605. { sets d/a port from string}
  606.  
  607. var i,j:integer;
  608.  
  609. begin {get_daport}
  610.     if (s='LPT2') or (s='lpt2') then
  611.       get_daport:=lpt2
  612.     else
  613.       if (s='LPT3') or (s='lpt3') then
  614.         get_daport:=lpt3
  615.       else
  616.         if (s='LPT1') or (s='lpt1') then
  617.           get_daport:=lpt1
  618.         else
  619.         begin
  620.           val(s,j,i);
  621.           if i>0 then
  622.           begin
  623.             closegraph;
  624.             writeln('Error in port address from ',cnffilename,' => ',s);
  625.             halt;
  626.           end;
  627.           get_daport:=j;
  628.         end;
  629. end; {get_daport}
  630.  
  631.  
  632. procedure display_status;
  633.  
  634. { displays status and version info in a title box}
  635.  
  636. var dp,dialoghead,lastdialogentry:dialogentryp;
  637.  
  638. begin {display_status}
  639.   dialoghead:=nil;
  640.   if getmaxy>200 then
  641.   begin
  642.     new(dp);
  643.     with dp^ do
  644.     begin
  645.       title:='  '+titlestring;
  646.       argtype:=_none;
  647.       add_dialogentry(dp,lastdialogentry,dialoghead);
  648.     end;
  649.   end;
  650.   new(dp);
  651.   with dp^ do
  652.   begin
  653.     title:='Current path:';
  654.     argtype:=_string;
  655.     nulvalid:=false;
  656.     stringresult:=path;
  657.     ssize:=length(titlestring)-11;
  658.     add_dialogentry(dp,lastdialogentry,dialoghead);
  659.   end;
  660.   new(dp);
  661.   with dp^ do
  662.   begin
  663.     title:='Current sound file:'+copy(bigemptystring,1,
  664.                           length(titlestring)-length(workfile)-16)+workfile;
  665.       argtype:=_none;
  666.     add_dialogentry(dp,lastdialogentry,dialoghead);
  667.   end;
  668.   new(dp);
  669.   with dp^ do
  670.   begin
  671.     title:='Instrument type:';
  672.     argtype:=_string;
  673.     nulvalid:=false;
  674.     stringresult:=default_kbdmap;
  675.     ssize:=6;
  676.     add_dialogentry(dp,lastdialogentry,dialoghead);
  677.   end;
  678.   new(dp);
  679.   with dp^ do
  680.   begin
  681.     title:='Sytem type:';
  682.     argtype:=_string;
  683.     nulvalid:=false;
  684.     stringresult:=systemname;
  685.     ssize:=8;
  686.     add_dialogentry(dp,lastdialogentry,dialoghead);
  687.   end;
  688.   new(dp);
  689.   with dp^ do
  690.   begin
  691.     title:='Key release:';
  692.     argtype:=_boolean;
  693.     booleanresult:=releasestate;
  694.     add_dialogentry(dp,lastdialogentry,dialoghead);
  695.   end;
  696.   new(dp);
  697.   with dp^ do
  698.   begin
  699.     title:='Loop mode:';
  700.     argtype:=_boolean;
  701.     booleanresult:=loop;
  702.     add_dialogentry(dp,lastdialogentry,dialoghead);
  703.   end;
  704.   new(dp);
  705.   with dp^ do
  706.   begin
  707.     title:='Auto timer:';
  708.     argtype:=_boolean;
  709.     booleanresult:=timer;
  710.     add_dialogentry(dp,lastdialogentry,dialoghead);
  711.   end;
  712. {$ifdef sample}
  713.   new(dp);
  714.   with dp^ do
  715.   begin
  716.     title:='Trigger level:';
  717.     argtype:=_integer;
  718.     integerresult:=trigger;
  719.     add_dialogentry(dp,lastdialogentry,dialoghead);
  720.   end;
  721.   new(dp);
  722.   with dp^ do
  723.   begin
  724.     title:='Sample rate:';
  725.     argtype:=_integer;
  726.     integerresult:=samplerate;
  727.     add_dialogentry(dp,lastdialogentry,dialoghead);
  728.   end;
  729. {$endif}
  730.   new(dp);
  731.   with dp^ do
  732.   begin
  733.     title:='D/A port:';
  734.     argtype:=_string;
  735.     stringresult:=default_daport;
  736.     nulvalid:=false;
  737.     ssize:=4;
  738.     add_dialogentry(dp,lastdialogentry,dialoghead);
  739.   end;
  740.   if getmaxy<300 then
  741.   begin
  742.     setusercharsize(14,10,100,101);
  743.     settextstyle(smallfont,horizdir,usercharsize);
  744.   end
  745.   else
  746.     settextstyle(defaultfont,horizdir,1);
  747.   dialog_box(dialoghead,dialogbcolor,dialogcolor,true);
  748.   dp:=dialoghead;
  749.   if getmaxy>200 then
  750.     dp:=dp^.next;
  751.   path:=dp^.stringresult;
  752.   dp:=dp^.next;
  753.   dp:=dp^.next;
  754.   default_kbdmap:=dp^.stringresult;
  755.   dp:=dp^.next;
  756.   systemname:=dp^.stringresult;
  757.   while (systemname[1]=' ') and (length(systemname)>1) do
  758.     delete(systemname,1,1);
  759.   case upcase(systemname[1]) of
  760.     'X': if (length(systemname)>4) and (systemname[5]<>' ') then
  761.            select_system('T')
  762.          else
  763.            select_system('X');
  764.     'A': if (length(systemname)>4) and (systemname[5]<>' ') then
  765.            select_system('U')
  766.          else
  767.            select_system('A');
  768.   end; {case}
  769.   dp:=dp^.next;
  770.   releasestate:=dp^.booleanresult;
  771.   dp:=dp^.next;
  772.   loop:=dp^.booleanresult;
  773.   dp:=dp^.next;
  774.   timer:=dp^.booleanresult;
  775. {$ifdef sample}
  776.   dp:=dp^.next;
  777.   trigger:=dp^.integerresult;
  778.   dp:=dp^.next;
  779.   samplerate:=dp^.integerresult;
  780. {$endif}
  781.   dp:=dp^.next;
  782.   default_daport:=dp^.stringresult;
  783.   daout:=get_daport(default_daport);
  784.   dispose_dialog(dialoghead);
  785. end; {display_status}
  786.  
  787.  
  788.  
  789.   Procedure initialise;
  790.  
  791.     { initialise global variables etc}
  792.  
  793.   Var i,j:integer;
  794.  
  795.   Begin
  796.     WriteLn;
  797.     WriteLn('   ', titlestring);
  798.     WriteLn;
  799.     WriteLn;
  800.     Assign(cnffile, cnffilename);
  801.     {$i-} Reset(cnffile); {$i+}
  802.     If IoResult <> 0 Then
  803.       Begin
  804.         WriteLn('Error opening configuration file ', cnffilename);
  805.         Halt;
  806.       End;
  807.  
  808.     songfilename:='';
  809.     new(buffer);                  {create sound storage buffer}
  810.     new(bufferw);                   {create buffer overflow space}
  811.     new(dummy);                    {creat overflow area AFTER bufferw}
  812.     ReadLn(cnffile, path);
  813.     ReadLn(cnffile, default_sound_file);
  814.     ReadLn(cnffile, default_system);
  815.     ReadLn(cnffile, default_daport);
  816.     ReadLn(cnffile, default_kbdmap);
  817.     if path='' then
  818.       path:='.';
  819.     quickexit:=false;
  820.     filesavail := 0;
  821.     zoom:=false;
  822.     goodbye:=false;
  823.     loop := False;
  824.     timer := False;
  825.     song:=false;
  826.     trigger := 200;                 {set trigger to reasonable level}
  827.     select_system(Upcase(default_system));
  828.     tinterval:=crotchet;        {set note duration to crotchet (if timer used)}
  829.     copying := False;
  830.     songspeed:=1.0;               {defauult song speed}
  831.     kbdmode:=false;
  832.     kbdflag := 0;
  833.     keyval := 0;
  834.     release:=true;
  835.     releasestate := True;              {sensitive to key release}
  836.     cutboxactive:=false;
  837.     cutactive:=false;
  838.     bufflen:=bufflength;
  839.  
  840.     graphdriver := detect;
  841.     If (registerbgifont(@triplexfontproc) < 0) Or
  842.     (registerbgifont(@smallfontproc) < 0) Then
  843.       Begin
  844.         WriteLn('Error loading font');
  845.         Halt;
  846.       End;
  847.     If (registerbgidriver(@hercdriverproc) < 0) Or
  848.     (registerbgidriver(@cgadriverproc) < 0) Or
  849.     (registerbgidriver(@egavgadriverproc) < 0) Then
  850.       Begin
  851.         WriteLn('Error loading driver');
  852.         Halt;
  853.       End;
  854.  
  855.     initgraph(graphdriver, graphmode, 'c:\language\turbop4\grf');
  856.  
  857.     settextstyle(smallfont,horizdir,4);
  858.     wavescale := 1 - Ord(getmaxy > 300) + 2;
  859.     if getmaxy >200 then
  860.       wavebottom := getmaxy-textheight(' ')*9
  861.     else
  862.       wavebottom := getmaxy-textheight(' ')*6;
  863.     wavetop:=wavebottom-255 div wavescale;
  864.     arrowlowy := wavebottom + 2;
  865.     arrowhighy := wavebottom - 256 Div wavescale - arrowysize - 2;
  866.  
  867.     drawpoly(arrowpoints, uparrowshape); {draw up arrow}
  868.     fillpoly(arrowpoints, uparrowshape); {fill   "     }
  869.     GetMem(uparrowp, imagesize(0, 0, arrowxsize, arrowysize));
  870.     getimage(0, 0, arrowxsize, arrowysize, uparrowp^); {save arrow image}
  871.     drawpoly(arrowpoints, downarrowshape); {draw down arrow on the right}
  872.     fillpoly(arrowpoints, downarrowshape);
  873.     GetMem(downarrowp, imagesize(0, 0, arrowxsize, arrowysize));
  874.     getimage(100, 0, 100 + arrowxsize, arrowysize, downarrowp^); {save image}
  875.  
  876.     cleardevice;
  877.     initpointer;
  878.  
  879.     settextstyle(smallfont, horizdir, 4);
  880.     settextjustify(lefttext, toptext);
  881.     for j:=1 to noheadings do  {make storage for image under menu bars}
  882.       for i:=2 to maxverticalbars do
  883.         if menustructure[j].entry[i].selection<>inactive then
  884.           GetMem(menustorage[j].entry[i],
  885.                  imagesize(0,0,(getmaxx-cornersize*2) div noheadings,
  886.                            round(textheight(' ')*1.5)-1));
  887.  
  888.     fill_background(screencolor,interleavefill,cornersize);
  889.     display_title(titlestring,triplexfont,4,panelcolor,titlecolor);
  890.     settextstyle(smallfont, horizdir, 4);
  891.     settextjustify(lefttext, centertext);
  892.     dirnamesperline := (getmaxx - cornersize * 2)
  893.                        Div (dirnamefieldwidth * textwidth(' '));
  894.     panel(getmaxx div 2,getmaxy div introyoff-textheight(' '),
  895.           getmaxx-cornersize*2,textheight(' ')*8,panelcolor);
  896.     settextstyle(defaultfont, horizdir, 1);
  897.     selectcolor(black);
  898.  
  899.     daout:=get_daport(default_daport);
  900.  
  901. {$ifndef pwm}
  902.     outtextxy(cornersize,getmaxy div introyoff,' D/A converter is on '
  903.               +default_daport);
  904. {$endif pwm}
  905.  
  906.     outtextxy(cornersize, getmaxy Div introyoff + textheight(' ') * 2,
  907.               ' Sound files path is ' + path);
  908.  
  909.     If (default_kbdmap = 'guitar') Or (default_kbdmap = 'GUITAR') Then
  910.       Begin
  911.         default_kbdmap := 'guitar';
  912.         kbdmap := kbdmapguitar;
  913.       End;
  914.     If default_kbdmap <> 'guitar' Then
  915.       Begin
  916.         default_kbdmap := 'piano ';
  917.         kbdmap := kbdmappiano;
  918.       End;
  919.  
  920.     outtextxy(cornersize, getmaxy Div introyoff + textheight(' ') * 4,
  921.               ' Using keyboard map for ' + default_kbdmap);
  922.     outtextxy(cornersize, getmaxy Div introyoff + textheight(' ') * 6,
  923.               ' Reading default sound file ' + default_sound_file+'...');
  924.  
  925.     mousearrowon;
  926.     cut_region(index(plotxoffset),index(getmaxx-plotxoffset)); {clear buffer}
  927.     leftord:=0;
  928.     rightord:=0;
  929.     loopord:=0;
  930.     load_sound_file(default_sound_file,index(plotxoffset),
  931.                     index(getmaxx-plotxoffset),false);
  932.     viewleft:=index(plotxoffset);
  933.     viewright:=index(getmaxx-plotxoffset);
  934.     samplerate:=default_samplerate;
  935.     i:=0;
  936.     display_status;
  937.     mousearrowoff;
  938.  
  939.     settextstyle(defaultfont,horizdir,1);
  940.     tuningcp:=nil;
  941.     new(cp);
  942.     cp^.ttype:=_text;
  943.     cp^.x:=0;
  944.     cp^.y:=0;
  945.     cp^.title:=#25;
  946.     add_clickboxentry(cp,lastcp,tuningcp);
  947.     new(cp);
  948.     cp^.ttype:=_figure;
  949.     cp^.x:=textwidth('    ');
  950.     cp^.y:=0;
  951.     cp^.numpoints:=tuningshapepoints;
  952.     cp^.polypoints:=@tuninglshape;
  953.     cp^.fill:=true;
  954.     add_clickboxentry(cp,lastcp,tuningcp);
  955.     new(cp);
  956.     cp^.ttype:=_text;
  957.     cp^.x:=textwidth('       ');
  958.     cp^.y:=0;
  959.     cp^.title:=#17;
  960.     add_clickboxentry(cp,lastcp,tuningcp);
  961.     new(cp);
  962.     cp^.ttype:=_text;
  963.     cp^.x:=textwidth('          ');
  964.     cp^.y:=0;
  965.     cp^.title:=#16;
  966.     add_clickboxentry(cp,lastcp,tuningcp);
  967.     new(cp);
  968.     cp^.ttype:=_figure;
  969.     cp^.x:=textwidth('             ');
  970.     cp^.y:=0;
  971.     cp^.numpoints:=tuningshapepoints;
  972.     cp^.polypoints:=@tuningrshape;
  973.     cp^.fill:=true;
  974.     add_clickboxentry(cp,lastcp,tuningcp);
  975.     new(cp);
  976.     cp^.ttype:=_text;
  977.     cp^.x:=textwidth('                 ');
  978.     cp^.y:=0;
  979.     cp^.title:=#24;
  980.     add_clickboxentry(cp,lastcp,tuningcp);
  981.     new(cp);
  982.     cp^.ttype:=_text;
  983.     cp^.x:=textwidth('                     ');
  984.     cp^.y:=0;
  985.     cp^.title:='Reset';
  986.     add_clickboxentry(cp,lastcp,tuningcp);
  987.     new(cp);
  988.     cp^.ttype:=_text;
  989.     cp^.x:=textwidth('      ');
  990.     cp^.y:=-textheight(' ')*2;
  991.     cp^.title:='Tuning';
  992.     add_clickboxentry(cp,lastcp,tuningcp);
  993.  
  994.     timercp:=nil;
  995.     new(cp);
  996.     cp^.ttype:=_figure;
  997.     cp^.x:=0;
  998.     cp^.y:=0;
  999.     cp^.numpoints:=tuningshapepoints;
  1000.     cp^.polypoints:=@tuninglshape;
  1001.     cp^.fill:=true;
  1002.     add_clickboxentry(cp,lastcp,timercp);
  1003.     new(cp);
  1004.     cp^.ttype:=_text;
  1005.     cp^.x:=textwidth('   ');
  1006.     cp^.y:=0;
  1007.     cp^.title:=#17;
  1008.     add_clickboxentry(cp,lastcp,timercp);
  1009.     new(cp);
  1010.     cp^.ttype:=_text;
  1011.     cp^.x:=textwidth('      ');
  1012.     cp^.y:=0;
  1013.     cp^.title:=#16;
  1014.     add_clickboxentry(cp,lastcp,timercp);
  1015.     new(cp);
  1016.     cp^.ttype:=_figure;
  1017.     cp^.x:=textwidth('         ');
  1018.     cp^.y:=0;
  1019.     cp^.numpoints:=tuningshapepoints;
  1020.     cp^.polypoints:=@tuningrshape;
  1021.     cp^.fill:=true;
  1022.     add_clickboxentry(cp,lastcp,timercp);
  1023.     new(cp);
  1024.     cp^.ttype:=_text;
  1025.     cp^.x:=textwidth('  ');
  1026.     cp^.y:=-textheight(' ')*2;
  1027.     cp^.title:=' Timer';
  1028.     add_clickboxentry(cp,lastcp,timercp);
  1029.  
  1030.   End;   {initialise}
  1031.  
  1032.  
  1033.  
  1034.   Procedure update_settings;
  1035.  
  1036.     { write settings on screen}
  1037.  
  1038.   Var str1,str2 : String;
  1039.     h : Integer;
  1040.  
  1041.   Begin
  1042.     settextstyle(smallfont,horizdir,4);
  1043.     h:=textheight(' ')*3;
  1044.     settextjustify(centertext, toptext);
  1045.     selectcolor(black);
  1046.     settextstyle(defaultfont, horizdir, 1);
  1047.     panel(getmaxx Div 2, h - Round(textheight(' ') * 0.25), getmaxx -cornersize*2,
  1048.           Round(textheight(' ') * 3.5),panelcolor);
  1049.     outtextxy(getmaxx div 2,h,'Current status:     ');
  1050.  
  1051.     str1:='';
  1052.  
  1053. {$ifdef sample}
  1054.     str(trigger,str2);
  1055.     str1:=str1 + ' Trigger:   '+str2;
  1056. {$endif}
  1057.  
  1058.     settextjustify(lefttext, toptext);
  1059.     outtextxy(cornersize, h +textheight(' '),str1+
  1060.              '   Path: ' + path +
  1061.              '    File: ' + workfile);
  1062.  
  1063.     If loop Then
  1064.       str1 := ' Loop mode:  on'
  1065.     Else
  1066.       str1 := ' Loop mode: off';
  1067.     If releasestate Then
  1068.       str1 := str1 + '   Key release:  on'
  1069.     Else
  1070.       str1 := str1 + '   Key release: off';
  1071.     If timer Then
  1072.       str1 := str1 + '   Auto timer:  on'
  1073.     Else
  1074.       str1 := str1 + '   Auto timer: off';
  1075.  
  1076. {$ifdef sample}
  1077.     str(samplerate,str2);
  1078.     str1:=str1+ '   Sample rate: '+str2+'kHz';
  1079. {$endif}
  1080.  
  1081.     outtextxy(cornersize, h + textheight(' ')*2, str1);
  1082.   End;    {update_settings}
  1083.  
  1084.  
  1085. procedure draw_wave;
  1086.  
  1087. { draws wave box and wave form. clear indicates whether background should be
  1088.  cleared first}
  1089.  
  1090.   Var lasty, y,i : Integer;
  1091.     ratio : Real;
  1092.  
  1093. begin {draw_wave}
  1094.     ratio := (viewright-viewleft)/ (getmaxx - 2 * plotxoffset);
  1095.     selectfillstyle(solidfill, black);
  1096.     setlinestyle(solidln, 0, normwidth);
  1097.     selectcolor(waveboxcolor);
  1098.     bar(0, arrowlowy + arrowysize + 2, getmaxx, arrowhighy - 2);
  1099.     rectangle(plotxoffset, wavebottom + 1, getmaxx - plotxoffset,
  1100.               wavetop- 1);
  1101.     rectangle(0, arrowlowy + arrowysize + 2, getmaxx, arrowhighy - 2);
  1102.     selectcolor(wavecolor);
  1103.     moveto(plotxoffset,wavebottom-buffer^[viewleft] div wavescale);
  1104.     For i := 1 To getmaxx - plotxoffset*2 Do
  1105.       lineto(i+plotxoffset,
  1106.              wavebottom - buffer^[Round(i * ratio)+viewleft] Div wavescale);
  1107.     display_pointers(leftord,rightord,loopord,true,true,true);
  1108. {$ifdef pwm}
  1109.     scalewave;
  1110. {$endif {pwm}
  1111. end; {draw_wave}
  1112.  
  1113.   Procedure update_display;
  1114.  
  1115.     { refresh graphics screen}
  1116.  
  1117.   Begin
  1118.     fill_background(screencolor,interleavefill,cornersize);
  1119.     update_settings;
  1120.     draw_wave;
  1121.     draw_menu_headers;
  1122.     settextstyle(defaultfont,horizdir,1);
  1123.     draw_clicklist(tuningcp,cornersize,getmaxy-textheight(' ')*2,tuningbcolor,
  1124.                    tuningcolor);
  1125.     draw_clicklist(timercp,getmaxx-cornersize-textwidth('            '),
  1126.                    getmaxy-textheight(' ')*2,timerbcolor,
  1127.                    timercolor);
  1128.   End;  {update_display}
  1129.  
  1130.  
  1131.     PROCEDURE parsesong;
  1132.  
  1133.     { parse a Pianoman MUS file and save in song structure}
  1134.  
  1135.     var storagep:pointer;
  1136.         dp:dialogentryp;
  1137.  
  1138.     BEGIN {parsesongfile}
  1139.  
  1140.     songp := 1;
  1141.     while not eof(fsong) and (songp<=maxbeats) do
  1142.     begin
  1143.       read(fsong,anote);
  1144.       songarray[songp].note:=
  1145.        Exp(((anote.octave-3)*12+anote.note-20)* 0.057762265); {convert pianoman
  1146.                                                            note to keyboard note
  1147.                                                            ('Z'=>-12)}
  1148.       if anote.note=13 then
  1149.         songarray[songp].note:=-13;
  1150.       songarray[songp].duration:=
  1151.                             round(anote.duration/1700*162/sysspeed*crotchet);
  1152.                                 {scale duration also. note sysspeed takes
  1153.                                 account of system speed dependence of Pianoman.
  1154.                                 1700 is a typical pianoman crotchet length for
  1155.                                 my at turbo, 162 is sysspeed for an at turbo}
  1156.       inc(songp);
  1157.       if songp>maxbeats then
  1158.       begin
  1159.             new(dp);
  1160.             with dp^ do
  1161.             begin
  1162.               title:='Song too big - truncating';
  1163.               argtype:=_none;
  1164.               next:=nil;
  1165.             end;
  1166.             settextstyle(defaultfont,horizdir,1);
  1167.             dialog_box(dp,dialogbcolor,dialogcolor,true);
  1168.             dispose(dp);
  1169.       end;
  1170.     end;
  1171.     songend := Pred(songp);
  1172.     END;                      {parsesongfile}
  1173.  
  1174.  
  1175.     procedure loadsong;
  1176.  
  1177.     { loads and parses a song file}
  1178.  
  1179.     var storagep:pointer;
  1180.         dp:dialogentryp;
  1181.  
  1182.     begin
  1183.       pickfile('MUS',songfilename);
  1184.       mousearrowoff;
  1185.       display_message('Loading '+songfilename,
  1186.                        dialogbcolor,dialogcolor,storagep,true);
  1187.       if songfilename<>'' then
  1188.       begin
  1189.         if (songfilename[1]='\') or (songfilename[2]=':') then
  1190.           Assign(fsong, songfilename)
  1191.         else
  1192.           Assign(fsong, path+'\'+songfilename);
  1193.         {$i-}
  1194.         Reset(fsong);
  1195.         {$i+}
  1196.         IF IOResult = 0 THEN
  1197.         begin
  1198.           parsesong;
  1199.           Close(fsong);     {must do this incase another read (assign) later}
  1200.         end
  1201.         else
  1202.         begin
  1203.           beep;
  1204.             new(dp);
  1205.             with dp^ do
  1206.             begin
  1207.               title:='File not found ('+songfilename+')';
  1208.               argtype:=_none;
  1209.               next:=nil;
  1210.             end;
  1211.             settextstyle(defaultfont,horizdir,1);
  1212.             dialog_box(dp,dialogbcolor,dialogcolor,true);
  1213.             dispose(dp);
  1214.           songfilename:='';
  1215.         end;
  1216.       end;
  1217.       display_message('Loading '+songfilename,
  1218.                        dialogbcolor,dialogcolor,storagep,false);
  1219.       update_display;
  1220.       mousearrowon;
  1221.     end; {loadsong}
  1222.  
  1223. function arrow_selection:integer;
  1224.  
  1225. { determines whether mouse is over a wave box arrow}
  1226.  
  1227. begin {arrow_selection}
  1228. if (mousex>=scaleord(leftord)-arrowxoff) and
  1229.    (mousex<=scaleord(leftord)-arrowxoff+arrowxsize) and
  1230.    (mousey>=arrowlowy) and (mousey<=arrowlowy+arrowysize) then
  1231.   arrow_selection:=1
  1232. else
  1233. if (mousex>=scaleord(rightord)-arrowxoff) and
  1234.    (mousex<=scaleord(rightord)-arrowxoff+arrowxsize) and
  1235.    (mousey>=arrowlowy) and (mousey<=arrowlowy+arrowysize) then
  1236.   arrow_selection:=2
  1237. else
  1238. if (mousex>=scaleord(loopord)-arrowxoff) and
  1239.    (mousex<=scaleord(loopord)-arrowxoff+arrowxsize) and
  1240.    (mousey>=arrowhighy) and (mousey<=arrowhighy+arrowysize) then
  1241.   arrow_selection:=3
  1242. else
  1243.   arrow_selection:=-1;
  1244. end; {arrow_selection}
  1245.  
  1246.  
  1247. procedure erase_cutbox;
  1248.  
  1249. { erases cut box, restoring waveform}
  1250.  
  1251. var j:longint;
  1252.  
  1253. begin {erase_cutbox}
  1254. if cutboxactive then
  1255. begin
  1256.   for j:=wavetop-1 to wavebottom+1 do
  1257.     putpixel(scaleord(cutleft),j,getmaxcolor-getpixel(scaleord(cutleft),j));
  1258.   if cutleft<>cutright then
  1259.     for j:=wavetop-1 to wavebottom+1 do
  1260.       putpixel(scaleord(cutright),j,getmaxcolor-getpixel(scaleord(cutright),j));
  1261.   selectcolor(waveboxcolor);
  1262.   line(scaleord(cutleft)-1,wavetop-1,scaleord(cutright)+1,wavetop-1);
  1263.   line(scaleord(cutleft)-1,wavebottom+1,scaleord(cutright)+1,wavebottom+1);
  1264. end;
  1265. end; {erase_cutbox}
  1266.  
  1267.  
  1268. procedure draw_cutbox;
  1269.  
  1270. { draws cut box}
  1271.  
  1272. var j:longint;
  1273.  
  1274. begin {draw_cutbox}
  1275. if cutboxactive then
  1276. begin
  1277.   for j:=wavetop-1 to wavebottom+1 do
  1278.     putpixel(scaleord(cutleft),j,getmaxcolor-getpixel(scaleord(cutleft),j));
  1279.   if cutleft<>cutright then
  1280.     for j:=wavetop-1 to wavebottom+1 do
  1281.       putpixel(scaleord(cutright),j,getmaxcolor-getpixel(scaleord(cutright),j));
  1282.   for j:=scaleord(cutleft)+1 to scaleord(cutright)-1 do
  1283.     if (getmaxcolor>1) or odd(j) then
  1284.     begin
  1285.       putpixel(j,wavetop-1,getmaxcolor-getpixel(j,wavetop-1));
  1286.       putpixel(j,wavebottom+1,getmaxcolor-getpixel(j,wavebottom+1));
  1287.     end;
  1288. end;
  1289. end; {draw_cutbox}
  1290.  
  1291. procedure activate_menu_options(state:boolean);
  1292.  
  1293. { enable/disable menu options requiring cut box}
  1294.  
  1295. begin {activate_menu_options}
  1296. menustructure[3].entry[2].visible:=state; {cut}
  1297. menustructure[3].entry[3].visible:=state; {copy}
  1298. menustructure[3].entry[6].visible:=state; {mirror}
  1299. menustructure[3].entry[7].visible:=state; {envelope}
  1300. menustructure[3].entry[8].visible:=state; {clear}
  1301. if not zoom then
  1302.   menustructure[3].entry[9].visible:=state; {draw}
  1303. if cutactive and state then
  1304. begin
  1305.   menustructure[3].entry[4].visible:=true; {paste}
  1306.   menustructure[3].entry[5].visible:=true; {mix}
  1307. end
  1308. else
  1309. begin
  1310.   menustructure[3].entry[4].visible:=false;
  1311.   menustructure[3].entry[5].visible:=false;
  1312. end;
  1313. end; {activate_menu_options}
  1314.  
  1315.  
  1316.   Procedure mirror_data;
  1317.  
  1318.     { mirror sample data between pointers}
  1319.  
  1320.   Var temp : Byte;
  1321.     i, j : longInt;
  1322.  
  1323.   Begin
  1324.     settextstyle(defaultfont,horizdir,1);
  1325.     display_message('Calculating...',
  1326.                      dialogbcolor,dialogcolor,storagep,true);
  1327.     j:=cutright;
  1328.     For i := cutleft To (cutleft+cutright) shr 1 Do
  1329.       Begin
  1330.         temp := buffer^[i];        {temp}
  1331.         buffer^[i] := buffer^[j];
  1332.         buffer^[j] := temp;
  1333.         dec(j);
  1334.       End;
  1335.     display_message('Calculating...',
  1336.                      dialogbcolor,dialogcolor,storagep,false);
  1337.   End;    {mirror_data}
  1338.  
  1339.  
  1340.   Procedure scale_envelope;
  1341.  
  1342.     { scale sample data between points by an envelope formed by two end
  1343.     factors}
  1344.  
  1345.   Var j,i : longInt;
  1346.       k1 : Real;
  1347.       dp,dialoghead,lastdialogentry:dialogentryp;
  1348.  
  1349.   Begin
  1350.     dialoghead:=nil;
  1351.     new(dp);
  1352.     with dp^ do
  1353.     begin
  1354.       title:='Scale factor at left marker';
  1355.       argtype:=_real;
  1356.       decimalp:=2;
  1357.       realresult:=1;
  1358.       add_dialogentry(dp,lastdialogentry,dialoghead);
  1359.     end;
  1360.     new(dp);
  1361.     with dp^ do
  1362.     begin
  1363.       title:='Scale factor at right marker';
  1364.       argtype:=_real;
  1365.       decimalp:=2;
  1366.       realresult:=1;
  1367.       add_dialogentry(dp,lastdialogentry,dialoghead);
  1368.     end;
  1369.     settextstyle(defaultfont,horizdir,1);
  1370.     dialog_box(dialoghead,dialogbcolor,dialogcolor,true);
  1371.     If not ((dialoghead^.realresult = 1) and (dialoghead^.next^.realresult=1))
  1372.     Then
  1373.     Begin
  1374.       display_message('Calculating...',
  1375.                       dialogbcolor,dialogcolor,storagep,true);
  1376.       For i := scaleord(cutleft) To Pred(scaleord(cutright)) Do
  1377.       Begin
  1378.         k1 := (dialoghead^.next^.realresult - dialoghead^.realresult)
  1379.               / (scaleord(cutright)-scaleord(cutleft))
  1380.               * (i - scaleord(cutleft)+ plotxoffset) + dialoghead^.realresult;
  1381.         For j := index(i) to index(i+1)-1 do
  1382.           buffer^[j] := lo(Round((buffer^[j] - 128) * k1 + 128));
  1383.       End;
  1384.       display_message('Calculating...',
  1385.                       dialogbcolor,dialogcolor,storagep,false);
  1386.     End;
  1387.     dispose_dialog(dialoghead);
  1388.   End;   {scale_envelope}
  1389.  
  1390.  
  1391.   Procedure write_data(fn:string; leftlimit,rightlimit:longint);
  1392.  
  1393.     { write sample data to disk file}
  1394.  
  1395.   Var f : File;
  1396.     i,j : longint;
  1397.     dp:dialogentryp;
  1398.  
  1399.   Begin
  1400.         mousearrowoff;
  1401.         settextstyle(defaultfont,horizdir,1);
  1402.         display_message('Writing file, please wait...', dialogbcolor,
  1403.                         dialogcolor,storagep,true);
  1404.         If pos('.', fn) = 0 Then
  1405.           fn := fn + '.snd';
  1406.         if (fn[1]<>'\') and (fn[2]<>':') then
  1407.           Assign(f, path+'\'+fn)
  1408.         else
  1409.           assign(f,fn);
  1410.         {$i-}
  1411.         Rewrite(f);
  1412.         {$i+}
  1413.         If IoResult = 0 Then
  1414.           Begin
  1415.             Move(buffer^[leftlimit], bufferw^[4],rightlimit-leftlimit);
  1416.                            {shift up to make space for preamble}
  1417.             bufferw^[0] := lo(rightlimit-leftlimit);
  1418.             bufferw^[1] := hi(rightlimit-leftlimit);
  1419.             bufferw^[2] := lo(loopord-leftlimit);
  1420.             bufferw^[3] := hi(loopord-leftlimit);
  1421.  
  1422.             i:=0;
  1423.             For i := 1 to ((rightlimit-leftlimit) div 128)
  1424.                           div (blocksize div 128) do
  1425.               blockwrite(f,bufferw^[pred(i)*blocksize],blocksize shr 7);
  1426.             for j:=1 to ((rightlimit-leftlimit-1) div 128 +1)
  1427.                         mod (blocksize div 128) do
  1428.               BlockWrite(f, bufferw^[i*blocksize+pred(j)*128], 1);
  1429.             Close(f);
  1430.           End
  1431.         Else
  1432.           Begin
  1433.             beep;
  1434.             new(dp);
  1435.             dp^.next:=nil;
  1436.             dp^.title:='Disk write error';
  1437.             dp^.argtype:=_none;
  1438.             mousearrowon;
  1439.             dialog_box(dp,dialogbcolor,dialogcolor,true);
  1440.             mousearrowoff;
  1441.             dispose(dp);
  1442.           End;
  1443.         display_message('Writing file, please wait...', dialogbcolor,
  1444.                         dialogcolor,storagep,false);
  1445.         mousearrowon;
  1446.   End;    {write_data}
  1447.  
  1448.  
  1449.  
  1450.  
  1451.